/*******************************************************************************
 *
 *      Filename: Log.cpp
 *   Description: See Log.h
 *        Author: [kb]ypp
 *    Created at: September 28, 2005
 * Last modified: November 26, 2005
 *
 ******************************************************************************/

#include "Log.h"
#include <iomanip>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;

// Constants used to format log message
static const int fileField = 15;
static const int lineField = 6;
static const int priorityField = 11;

//! May by called by Log::instance() function only.
//! @note (for Windows only) If the "log.txt" file does not exist
//! it will be created, otherwise it will be rewritten
Log::Log()
#ifndef _WIN32
	: out( &cerr )
#else
	: out( new ofstream( "log.txt" ) )
#endif
{
	writeHeader();
}

Log::~Log()
{
	if ( dynamic_cast< ofstream* >( out ) )
		delete out;
}

Log& operator<<( Log &log, const string &msg )
{
	*log.out << msg << endl;
	return log;
}

/*
void Log::outputTo( ostream &os )
{
	if ( out == &os )
		return;
	
	ofstream *p = dynamic_cast< ofstream* >( out );
	if ( p ) { // Logging to file?
		p->close();
		delete out;
	}
	out = &os;
	writeHeader();
}

void Log::outputTo( const string &filename )
{
	ofstream *p = dynamic_cast< ofstream* >( out );
	if ( p ) { // Logging to file?
		p->close();
		delete out;
	}
	out = new ofstream( filename.c_str() );
	writeHeader();
}
*/

void Log::writeHeader()
{
	ostringstream head;
	head.setf( ios::left, ios::adjustfield );
	head <<
		"--------------------------------------------------------------------------------\n"
		<< setw( fileField ) << " Filename" << '|'
		<< setw( lineField ) << " Line" << '|'
		<< setw( priorityField ) << " Priority" << '|'
		<< " Message\n" <<
		"--------------------------------------------------------------------------------\n";
	*out << head.str();
}

LogHelper::LogHelper( Log::MsgPriority pr, const string &file, int line )
{
	static string tags[ Log::NUM_LEVELS ] = {
		"EMERGENCY", "ALERT", "CRITICAL", "ERROR",
		"WARNING", "NOTICE", "INFO", "DEBUG"
	};
	ostringstream os;
	os.setf( ios::left, ios::adjustfield );
	os << ' ' << setw( fileField ) << file
	   << ' ' << setw( lineField ) << line
	   << ' ' << setw( priorityField ) << tags[ pr ]
	   << ' ';
	prefix = os.str();
}

LogHelper::LogHelper( const LogHelper &other )
	: prefix( other.prefix )
{}

const LogHelper& LogHelper::operator=( const LogHelper &other )
{
	prefix = other.prefix;
	return *this;
}

LogHelper& operator<<( LogHelper &lh, const std::string &msg )
{
	Log::instance() << ( lh.prefix + msg );
	return lh;
}
